/** This class creates a new Client-Socket and communices with this client 
 *  @author ChrM and Sun Microsystems */

package com.jtalker.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class JTalkerServerThread extends Thread {
	public Socket socket = null;
	public JTalkerServer parent;
	/** is a real member or connected? */
	private boolean hasValidMemberConnection = false;
	private PrintWriter out = null;
	private static int MAX_PACKET_SIZE = 410000;

	/** Constructor */
	public JTalkerServerThread(JTalkerServer parent, Socket socket) {
		super("JTalkerServerThread");
		this.parent = parent;
		this.socket = socket;
	}

	/** Gets Connections infos */
	public String getConnectionInfo() {
		String retVal = "TCP/IP: "
				+ this.socket.getInetAddress().getHostAddress();
		retVal += ":" + this.socket.getPort();

		/*
		 * if(this.getMember() != null) retVal += " / Name: " +
		 * this.getMember().getUserName();
		 * 
		 * retVal += " / #: " + this.parent.getNumOfMembers();
		 */
		return retVal;
	}

	/** Gets current member */
	public JTalkerMember getMember() {
		return this.parent.getMember(this.socket);
	}

	/** Sends the update request */
	public void sendUpdateRequest() {
		String message = JTalkerProtocol.getProcessString(5);
		this.getLogger().write(
				"+ Sending update msg to: " + getMember().getUserName());
		this.out.println(message);
	}

	public void run() {
		try {
			this.out = new PrintWriter(socket.getOutputStream(), true);
			BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

			String inputLine, outputLine;
			JTalkerProtocol protocol = new JTalkerProtocol(this);
			outputLine = protocol.processInput(null);
			this.out.println(outputLine);

			// Notify connection
			this.getLogger().write("(+) CONNECT: " + this.getConnectionInfo());

			try {
				while ((inputLine = in.readLine()) != null) {
					if (inputLine.length() > MAX_PACKET_SIZE) {
						if (this.getMember() != null) {
							this.getLogger().write(
									"*** Message to big (" + inputLine.length()
											+ " / max=" + MAX_PACKET_SIZE
											+ ") from "
											+ this.getMember().getUserInfo()
											+ ". Close connection.");
						}
						this.closeConnection(in, this.out);
						return;
					}
					outputLine = protocol.processInput(inputLine);
					this.out.println(outputLine);

					if (protocol.closeConnectionNow) {
						this.closeConnection(in, this.out);
						this.getLogger().write(
								"+ Protocol ends - close connection.");
						return;
					}

					// Real Member connects!
					if (this.getMember() != null) {
						// Update Session ID
						this.getMember().updateSessionID();
						this.getMember().setThread(this);

						// Notify login
						if (!this.hasValidMemberConnection) {
							this.getLogger().write(
									"+ MEMBER login: "
											+ this.getMember().getUserInfo());
							this.getLogger().write(
									"+ Number of connected members: "
											+ this.parent.getNumOfMembers());
							this.parent.sendUpdateRequestToAll(null);
							this.hasValidMemberConnection = true;
						}
					}
				}
			} catch (Exception e) {
				this.getLogger().write(
						"+ Client died... Exception: " + e.toString());
				e.printStackTrace();
				// this.closeConnection(in, out);
			}

			this.closeConnection(in, this.out);

		} catch (IOException e) {
			this.getLogger().writeError(
					"*** IOError Error in client thread (maybe a scan?): "
							+ e.toString());
		}
	}

	/** Close this socket */
	private void closeConnection(BufferedReader in, PrintWriter out) {
		try {
			out.close();
			in.close();
			this.getLogger().write(
					"(-) DISCONNECT: " + this.getConnectionInfo());
			// Don't remove webclients!!!
			if (this.getMember() != null) {
				// Notify login
				this.getLogger().write(
						"- MEMBER logout: " + this.getMember().getUserInfo());
				this.getLogger().write(
						"- Number of connected members: "
								+ (this.parent.getNumOfMembers() - 1));
				if (!this.getMember().getUserType()
						.equals(JTalkerMember.USER_TYPE_WEBCLIENT)) {
					this.parent.removeMember(this.socket.getPort());
				} else {
					this.getMember().isOnline = false;
				}
			}

			this.socket.close();

		} catch (Exception e) {
			this.getLogger().writeError(
					"*** Runtime Error: Can't close connection: "
							+ e.getMessage());
			e.printStackTrace();
		}

		this.parent.sendUpdateRequestToAll(null);
	}

	/** Gets the logger - passthru from parent */
	public Logger getLogger() {
		return this.parent.getLogger();
	}
}
